home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 4 / Example 4.4 / terrain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-01  |  5.1 KB  |  219 lines

  1. #include "terrain.h"
  2.  
  3. const DWORD TERRAINVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE;
  4.  
  5. //////////////////////////////////////////////////////////////////////////////////////////
  6. //                                    PATCH                                                //
  7. //////////////////////////////////////////////////////////////////////////////////////////
  8.  
  9. PATCH::PATCH()
  10. {
  11.     m_pDevice = NULL;
  12.     m_pMesh = NULL;
  13. }
  14. PATCH::~PATCH()
  15. {
  16.     Release();
  17. }
  18.  
  19. void PATCH::Release()
  20. {
  21.     if(m_pMesh != NULL)
  22.         m_pMesh->Release();
  23.     m_pMesh = NULL;
  24. }
  25.  
  26. HRESULT PATCH::CreateMesh(HEIGHTMAP &hm, RECT source, IDirect3DDevice9* Dev, int index)
  27. {
  28.     if(m_pMesh != NULL)
  29.     {
  30.         m_pMesh->Release();
  31.         m_pMesh = NULL;
  32.     }
  33.  
  34.     try
  35.     {
  36.         m_pDevice = Dev;
  37.  
  38.         int width = source.right - source.left;
  39.         int height = source.bottom - source.top;
  40.         int nrVert = (width + 1) * (height + 1);
  41.         int nrTri = width * height * 2;
  42.  
  43.         if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh)))
  44.         {
  45.             debug.Print("Couldn't create mesh for PATCH");
  46.             return E_FAIL;
  47.         }
  48.  
  49.         //Create vertices
  50.         TERRAINVertex* ver = 0;
  51.         m_pMesh->LockVertexBuffer(0,(void**)&ver);
  52.         for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++)
  53.             for(int x=source.left, x0 = 0;x<=source.right;x++, x0++)
  54.             {
  55.                 //Calculate vertex color
  56.                 float prc = hm.m_pHeightMap[x + z * hm.m_size.x] / hm.m_maxHeight;
  57.                 int red =  255 * prc;
  58.                 int green = 255 * (1.0f - prc);
  59.  
  60.                 D3DCOLOR col;
  61.  
  62.                 if(index % 2 == 0)        //Invert color depending on what patch it is...
  63.                     col = D3DCOLOR_ARGB(255, red, green, 0);
  64.                 else col = D3DCOLOR_ARGB(255, green, red, 0);
  65.  
  66.                 //Extract height (and position) from heightmap
  67.                 D3DXVECTOR3 pos = D3DXVECTOR3(x, hm.m_pHeightMap[x + z * hm.m_size.x], -z);
  68.  
  69.                 //Set new vertex
  70.                 ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, col);
  71.             }
  72.         m_pMesh->UnlockVertexBuffer();
  73.  
  74.         //Calculate Indices
  75.         WORD* ind = 0;
  76.         m_pMesh->LockIndexBuffer(0,(void**)&ind);    
  77.         int index = 0;
  78.  
  79.         for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++)
  80.             for(int x=source.left, x0 = 0;x<source.right;x++, x0++)
  81.             {
  82.                 //Triangle 1
  83.                 ind[index++] =   z0   * (width + 1) + x0;
  84.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  85.                 ind[index++] = (z0+1) * (width + 1) + x0;        
  86.  
  87.                 //Triangle 2
  88.                 ind[index++] = (z0+1) * (width + 1) + x0;
  89.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  90.                 ind[index++] = (z0+1) * (width + 1) + x0 + 1;
  91.             }
  92.  
  93.         m_pMesh->UnlockIndexBuffer();
  94.  
  95.         //Set Attributes
  96.         DWORD *att = 0;
  97.         m_pMesh->LockAttributeBuffer(0,&att);
  98.         memset(att, 0, sizeof(DWORD)*nrTri);
  99.         m_pMesh->UnlockAttributeBuffer();
  100.  
  101.         //Compute normals
  102.         D3DXComputeNormals(m_pMesh, NULL);
  103.     }
  104.     catch(...)
  105.     {
  106.         debug.Print("Error in PATCH::CreateMesh()");
  107.         return E_FAIL;
  108.     }
  109.  
  110.     return S_OK;
  111. }
  112.  
  113. void PATCH::Render()
  114. {
  115.     //Draw mesh
  116.     if(m_pMesh != NULL)
  117.         m_pMesh->DrawSubset(0);
  118. }
  119.  
  120. //////////////////////////////////////////////////////////////////////////////////////////
  121. //                                    TERRAIN                                                //
  122. //////////////////////////////////////////////////////////////////////////////////////////
  123.  
  124. TERRAIN::TERRAIN()
  125. {
  126.     m_pDevice = NULL;
  127. }
  128.  
  129. void TERRAIN::Init(IDirect3DDevice9* Dev, INTPOINT _size)
  130. {
  131.     m_pDevice = Dev;
  132.     m_size = _size;
  133.     m_pHeightMap = NULL;
  134.     GenerateRandomTerrain(3);    
  135. }
  136.  
  137. void TERRAIN::Release()
  138. {
  139.     for(int i=0;i<m_patches.size();i++)
  140.         if(m_patches[i] != NULL)
  141.             m_patches[i]->Release();
  142.  
  143.     m_patches.clear();
  144.  
  145.     if(m_pHeightMap != NULL)
  146.     {
  147.         m_pHeightMap->Release();
  148.         delete m_pHeightMap;
  149.         m_pHeightMap = NULL;
  150.     }
  151. }
  152.  
  153. void TERRAIN::GenerateRandomTerrain(int numPatches)
  154. {
  155.     try
  156.     {
  157.         Release();
  158.  
  159.         //Create two heightmaps and multiply them
  160.         m_pHeightMap = new HEIGHTMAP(m_size, 15.0f);
  161.         HEIGHTMAP hm2(m_size, 30.0f);
  162.  
  163.         m_pHeightMap->CreateRandomHeightMap(rand()%2000, 2.5f, 0.5f, 8);
  164.         hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.7f, 3);
  165.         hm2.Cap(hm2.m_maxHeight * 0.4f);
  166.  
  167.         *m_pHeightMap *= hm2;
  168.         hm2.Release();
  169.  
  170.         CreatePatches(numPatches);
  171.     }
  172.     catch(...)
  173.     {
  174.         debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
  175.     }
  176. }
  177.  
  178. void TERRAIN::CreatePatches(int numPatches)
  179. {
  180.     try
  181.     {
  182.         //Clear any old m_patches
  183.         for(int i=0;i<m_patches.size();i++)
  184.             if(m_patches[i] != NULL)
  185.                 m_patches[i]->Release();
  186.         m_patches.clear();
  187.  
  188.         if(m_pHeightMap == NULL)return;
  189.  
  190.         //Create new patches
  191.         for(int y=0;y<numPatches;y++)
  192.             for(int x=0;x<numPatches;x++)
  193.             {
  194.                 RECT r = {x * (m_size.x - 1) / (float)numPatches, 
  195.                         y * (m_size.y - 1) / (float)numPatches, 
  196.                         (x+1) * (m_size.x - 1) / (float)numPatches,
  197.                         (y+1) * (m_size.y - 1) / (float)numPatches};
  198.                         
  199.                 PATCH *p = new PATCH();
  200.                 p->CreateMesh(*m_pHeightMap, r, m_pDevice, x + y);
  201.                 m_patches.push_back(p);
  202.             }
  203.     }
  204.     catch(...)
  205.     {
  206.         debug.Print("Error in TERRAIN::CreatePatches()");
  207.     }
  208. }
  209.  
  210. void TERRAIN::Render()
  211. {
  212.     //Set render states
  213.     m_pDevice->SetRenderState(D3DRS_LIGHTING, true);
  214.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  215.  
  216.     //Render Patches
  217.     for(int i=0;i<m_patches.size();i++)
  218.         m_patches[i]->Render();
  219. }